/*
 * horizontalScroll - jQuery Plugin
 * http://plugins.jquery.com/project/horizontalScroll
 * http://drbroad.com   - coming soon!
 *
 * Copyright (c) 2011 Marc Broad (www.marcbroad.com / www.dystopia.co.nz / www.myopia.co.nz)
 * Licensed under the GNU GPL license
 *
 * $Date: Sun, 20th Feb 2011
 * $version: 1.0.0
 * 
 * A jQuery plugin to scroll horizontally using the vertical scroll bar. Combined with mobile tection it will also capture left, right, up and down swipes on touch devices.
 * Options:
 *		debug 		Boolean		Default false. 	If true, the default swipe handler will log to the console when triggered.
 *
 * This plugin will run ONLY on desktop browsers unless you include the mobile device detect php code from http://detectmobilebrowsers.mobi/
 * After, this jQuery plugin will then use swipe gestures on devices running Mobile Webkit based browsers (iOS 2.0+, android 2.2+)
 */
(function($){
 
    var methods = {
        
        init    : function(options){
            window.log('horizontal scroll init');           

           // replace the default settings...
            if ( options ) { 
                $.extend( settings, options );
            }
            
            // check for mobile platform:
            if($(settings.scrollWrapper).hasClass('mob')) config.mobile = true;
            //config.mobile = true;
            //$(settings.scrollWrapper).addClass('mob');
            
            //make the bg tile container bg fixed as to not scroll
            $(settings.bgImg).css({'background-attachment':'fixed'});
            
            //hide the scrollable elements while we set up...
            $(settings.scrollWrapper).css({'visibility':'hidden'});
            
            // make all the descriptions dull by default
            $(settings.scrDescriptions + ' div').addClass('dullText');
            
            // determing how many items we have to loop through
            config.sections = $(settings.scrollableContainer+':first div').length;
            
            // this sets up and enables the swiping options...
            $(settings.scrollWrapper).swipe( {swipe	:	$.swipe,		threshold	:	0} );

            // lets put the modal box in for the menu system
            $('<div id="scrollMenu"></div>').insertAfter(settings.scrollWrapper);
            $('#scrollMenu').css({
                'display'   :'none'
                });
            // insert the menu items to the menu
            $('#scrollMenu').html("<img src='/img/close.png' id='menuClose' alt='Close Menu'><ul></ul>");
            $('#menuClose').bind('click', $.swipeUp);
            
            var section =  $(settings.scrContent + ' div');            
            $(section + '[title]').each(function(){
            	$('#scrollMenu ul').append("<li><a data-menuNum='" + section.index(this) + "'>" + $(this).attr('title') + "</a></li>")
            });
            $('#scrollMenu li a').bind('click', $.gotoMenuItem);
            
            
            // if we arent on a mobile platform, make the vertical scroll div at the same height as the widest scrollable container
	    	if(!config.mobile){                
                $('<div id="vertScroll"></div>').insertBefore(settings.scrollWrapper);
                $('#vertScroll').css({
                                        'position'  :'absolute',
                                        'display'   :'block',
                                        'width'     :'1px',
                                        'visibility':'hidden'
                                    });
            }
	    	
	    	
        	// insert the desc bg div here         
            $('<div id="descBG"></div>').insertBefore(settings.scrDescriptions);
            $('#descBG').css({
                                    'position'  :'fixed',
                                    'display'   :'block',
                                    'float':'left',
                                    'background':' rgba(20, 20, 20, 0.8)',
                                    'height':'400px'
                                    });
 
	    	
            // set the widths and measurements
	    	$.setScrollerContainers(true);
            
            // reposition to account for the initial scroll
            $.respositionScrollers();
            
            $(settings.nextBtn).bind('click', $.nextItem);
            $(settings.prevBtn).bind('click', $.prevItem);
            
            $(document).keydown(function(e){
            	e.stopImmediatePropagation();
            	e.preventDefault();
            	
				switch(e.keyCode) { 
					// User pressed "left" arrow
					case 37:
					$.prevItem();
					break;
					   
					// User pressed "up" arrow
					case 38:
						$.navigateMenu('up')
					break;
					 
					// User pressed "right" arrow
					case 39:
					$.nextItem();
					break;	
					 
					// User pressed "down" arrow
					case 40:					

						if($('#scrollMenu').css('display') == 'none'){							
							var menuItems = $('#scrollMenu ul li');
							menuItems.removeClass('selected')
							var curSelected = menuItems[config.curSection]
							$(curSelected).addClass('selected');
							$.swipeDown();
						}else{
							// still showing, navigate the menu(down)
							$.navigateMenu('down')
						}
						
					break;
					 
					// User pressed "enter"
					case 13:
					        
					break;	
				}
            
            });
            
            $(window).bind('resize', $.onWindowResize);
            
            // if we are on the desktop, we want to reposition the scrollers on the scroll event
            if(!config.mobile){
            	$(window).bind('scroll', $.onScroll);		
            }
            
            // check if the anchor already exists, goto that section
            $.anchorItem();
            
            // make the scrollable wrapper visible again...
            $(settings.scrollWrapper).css({'visibility':'visible'});
        },
        
        next   : function(options){ 
        	$.nextItem();	
        },
        
        prev   : function(options){ 
        	$.prevItem();
        }
        
        /*
        up   : function(options){ 
        	$.swipeUp();	
        },
        
        down   : function(options){ 
        	$.swipeDown();
        } 
        */
    };
    
    
    var settings = {        
      scrollWrapper       		: '#horizontalScroller',   // the container that houses scrollable items
      scrollableContainer	: '.scrollContainer',     	  // these are the elements that contain items for scrolling
      
      disabledText		  		: 'dullText',       				 // this is the class that will make all the inactive text items dull
      
      scrContent 					: '#content',     				// the default container for the main content
      scrDescriptions 			: '#descriptions',     	 	// the default container for the descriptions
      bgImg			 				: '#bgImg',						// the default container for the background image
      useMobileBG			 	: false,								// if true, add '_mob' to the end of the bg img. so we can have smaller bg imgs just for phones.
      
      
      nextBtn           				 : '#nextItem',              // which element triggers to the next item
      prevBtn            				 : '#prevItem',              // which element triggers to the previous item  
      scrollbarMultiplier		 : 1								  // DESKTOP ONLY: this can be changed to make the scrollbar bigger or 
							      												  // shorter (this impacts the rate of scroll) based on your preference.
							      												  // for example: 0.5 would make the scrollbar half as long (faster scrolling)
							      												  // for example: 2 would make the scrollbar twice as long (slower scrolling)	    
    };
    
     var config = {        
        sections          : 0,        // the container that houses scrollable items
        curSection        : 999,        // the current section of the scrollable items
        prevSection       : 999,        // the previous section of the scrollable items        
        winHeight         : 0,        // the height of the window
        winWidth          : 0,        // the width of the window
        
        scrollPerc		  : 0, 		  // how far through the page are we. I chose to store this here for easy look up
        changeBG          : true,     // after snapping we check to see if the bg should be changed from this flag
        descBG				:'#descBG', // this is the background div for the
        checkSnap         : true,     // should i check to snap into place after a scroll event. To filter out program scrolls from manual scrolls
        snapScrollTimer	  : 0,		  // this is the timer that is used to snap the content into position after a manual scroll / resize
		mobile            : false     // is the site being viewed on a mobile platform
    };   

    
    $.fn.horizontalScroll = function( method ) {             
        // Method calling logic
        if ( methods[method] ) {
            return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else if ( typeof method === 'object' || ! method ) {
            return methods.init.apply( this, arguments );
        } else {
            var errorMsg = 'Method ' +  method + ' does not exist on fn.horizontalScroll...';
            $.error(errorMsg);
        }
    
        return this; 		
    }
    
    
    $.setScrollerContainers = function(init){        
        config.winWidth = $(window).width();
		config.winHeight = $(window).height();
        
        $(settings.scrContent + ' div').css('width', Math.round(0.9 * config.winWidth));
        
        $(settings.scrollableContainer).each(function(key, value) {                
            var container =  '#' + $(value).attr('id');
            
            
            // this only needs to be done once!!!
            
            if(init){
            	
	            $(value).children('div').each(function(key, value) {
	                $(value).attr('id', $(value).parent().attr('id') + key); 
	                $(value).css({'float':'left'});
	            });
            } 

            var itemWidth = $(container + " div").width() +
                            parseInt($(container + " div").css('margin-left').replace('px', '')) +
                            parseInt($(container + " div").css('margin-right').replace('px', ''));
                        
            $(container).css('width', itemWidth * config.sections);
            
            // need to set the content space in here....                   
        });
        
        config.contentScrollerWidth = $(settings.scrContent).width() * settings.scrollbarMultiplier; // + parseInt($('#content div').css('margin-left').replace('px', ''));
        if(!config.mobile )$('#vertScroll').css('height', config.contentScrollerWidth);
    }
    
    
    $.respositionScrollers = function(){     	     
        // set the bgImg container to the window height and width
      	$(settings.bgImg).width(config.winWidth).height(config.winHeight);
      	
      	 // align the descriptions to the bottom
        $(settings.scrDescriptions).css('top', config.winHeight - $(settings.scrDescriptions + ' div').height());
      	
       	
       	$(config.descBG).css({'top'			:config.winHeight - $(settings.scrDescriptions + ' div').height(), 
       												'height'	:$(settings.scrDescriptions + ' div').height()+ 'px',
       												'width'		:config.winWidth + 'px'});    
       	
       	
       	var currentScrollTop = $(window).scrollTop(); 
       	var scrollPerc = currentScrollTop / (config.contentScrollerWidth - config.winHeight);
       	
       	if(scrollPerc > 1) scrollPerc = 1;
       	if(scrollPerc < 0) scrollPerc = 0;	
       	
		// loop over the scroller containers and set the margin left 
		$(settings.scrollableContainer).each(function(key, value) { 
			               
		     var container =  '#' + $(value).attr('id');
    		 var contWidth =  $(container).width();		
			 var itemWidth =  contWidth / config.sections        
		     var pageBuffer = (config.winWidth - itemWidth) / 2;		     
		     var marginOffset = (0  - Math.round(((config.sections - 1) * itemWidth) * scrollPerc)) + pageBuffer;
	     
		     $(container).css("margin-left", marginOffset);
		});
		
		config.scrollPerc = scrollPerc;   
		
		//call the check scroller method to see if we need to snap into position
		$.checkScrollerForSnap();      
    }
    

    $.onWindowResize = function(evt){
        $.setScrollerContainers();
        $.respositionScrollers();    
    }
    
    
    $.onScroll = function(evt){
    	$.setScrollerContainers();
        $.respositionScrollers();    
    }
    

    $.toggleSection = function(sectionNum) {			
      
        if(sectionNum < 0) sectionNum = 0
        if(sectionNum >= config.sections-1) sectionNum = config.sections-1

        if(sectionNum != config.curSection){
            // set the title of the current viewed piece
            document.title = 'new section num: ' + sectionNum;
            location.href = "#" + sectionNum;
            
            $(settings.scrDescriptions+config.curSection).addClass(settings.disabledText);
            config.prevSection = config.curSection; 
            config.curSection = sectionNum; 
            $(settings.scrDescriptions+config.curSection).removeClass(settings.disabledText);
            
            // the section has changed, allow the bg change flag to be set true
            config.changeBG = true;                             
        }else{			
            // the section has NOT changed, set the bg change flag to false
            config.changeBG = false;		
        } 
        return config.changeBG;
    }
    

    $.nextItem = function() {
        if($.toggleSection(config.curSection + 1))  $.gotoItem(true, config.curSection)		
    }
    
    
    $.prevItem = function() {
    	  if($.toggleSection(config.curSection - 1)) $.gotoItem(true, config.curSection)
    }
    
    $.swipeUp = function() {
    	var duration = 400
    	if(config.mobile)duration=0    	
    	$('#scrollMenu').fadeOut(duration)
    }
    
    
    $.swipeDown = function() {
    	var duration = 400
    	if(config.mobile)duration=0
    	$('#scrollMenu').fadeIn(duration)
    }
    
    $.gotoMenuItem = function(evt){
    	// get the index of this from the list of a
    	/*
    	evt.preventDefault();
    	var $items = $('#scrollMenu ul li a')
    	window.log('goto item num: ' + $items.index(this));
    	var newSection = $items.index(this)
    	if($.toggleSection(newSection))  $.gotoItem(true, newSection)	
    	*/
    	var newSection = $(this).data('menuNum')
    	if($.toggleSection(newSection))  $.gotoItem(true, newSection)    	
    	$.swipeUp();
    }
    
    $.gotoItem = function(evtDriven, itemNum, duration) {

        if(duration === undefined) duration = 600;
        
        var transition = $(settings.scrContent+config.curSection).data('transition');
        if(!evtDriven)transition = 'slide'
        var targets = new Array();        
		$(settings.scrollableContainer).each(function(key, value) {     			
			var container =  '#' + $(value).attr('id');
    		var contWidth =  $(container).width();		
			var itemWidth =  contWidth / config.sections        
		    var pageBuffer = (config.winWidth - itemWidth) / 2;		     
			var targetX =   0 - (itemNum * itemWidth) + pageBuffer;			
			targets[$(value).attr('id')] = targetX;
		});       
        
        
        if(config.mobile){        	

        	// switch func
        	switch(transition)
        	{
        	case 'cut':
        		duration = 0;
        		$(settings.scrollableContainer).each(function(key, value) {
        			var container =  '#' + $(value).attr('id');
        			$(container).animate({marginLeft:targets[$(value).attr('id')]},{queue:false, duration:duration});
        		}); 
        	  break;
        	case 'fade':
        		$(settings.scrContent+config.curSection).add(settings.scrContent+config.prevSection).fadeTo(duration, 0, function(){
	        		$(settings.scrollableContainer).each(function(key, value) {
	        			var container =  '#' + $(value).attr('id');
	        			$(container).animate({marginLeft:targets[$(value).attr('id')]},{queue:false, duration:duration});
	        			setTimeout(function(){
	        				$(settings.scrContent+config.curSection).add(settings.scrContent+config.prevSection).fadeTo(duration, 1);	
	        			}, duration)
	        		});        	        		
        		}) 
        		
        	  break;
        	default:
        		$(settings.scrollableContainer).each(function(key, value) {
        			var container =  '#' + $(value).attr('id');
        			$(container).animate({marginLeft:targets[$(value).attr('id')]},{queue:false, duration:duration});
        		}); 
        	}

    		// set a timeout here instead of an oncomplete to make sure it only fires once...
    		setTimeout($.scrollSnapComplete, duration)
    		
        }else{        	
        	// document this later!        	
        	// work out the transition here.. 
        	var scrollPerc = (itemNum * (1/(config.sections - 1))) * (config.contentScrollerWidth - config.winHeight); 
        	config.checkSnap = false;      
        	
        	// switch func
        	switch(transition)
        	{
        	case 'cut':
        		$.scrollTo(scrollPerc, {speed:0, onAfter:$.scrollSnapComplete});
        	  break;
        	case 'fade':
        		
        		$(settings.scrContent+config.curSection).add(settings.scrContent+config.prevSection).fadeTo(duration, 0, function(){
        			$.scrollTo(scrollPerc, {speed:duration, onAfter:function(){
        				$(settings.scrContent+config.curSection).add(settings.scrContent+config.prevSection).fadeTo(duration, 1, function(){
        					$.scrollSnapComplete();
        				})        				
        			}})
        		})

        	  break;
        	default:
        		$.scrollTo(scrollPerc, {speed:duration, onAfter:$.scrollSnapComplete});
        	}
        	
            //$.scrollTo(scrollPerc, {speed:duration, onAfter:$.scrollSnapComplete});
        }
    }


	$.anchorItem = function() {		
		// get the anchor name
		var itemTarget = window.location.hash.substring(1);	
		
		
		if(itemTarget){	
			if($.toggleSection(parseInt(itemTarget))){
				
				// there is a hash on the url, and it is a different section to 0
				$.gotoItem(false, config.curSection);	
				clearTimeout(config.snapScrollTimer);
				return true;
				
			}
		}else{
			//$.toggleSection(0);
			//if($.toggleSection(0))
			$.gotoItem(false, 0);
			return false;
		}		
	}


	//Swipe handlers.
	//The only arg passed is the original touch event object		
	$.swipe = function(event, direction){
		//$(settings.bgImg).text("You swiped " + direction);
		if(direction === 'left') 	$.nextItem();
		if(direction === 'right')	$.prevItem();
		if(direction === 'up') 		$.swipeUp();
		if(direction === 'down')	$.swipeDown();
	} 

	$.checkScrollerForSnap = function() {
		
		if(config.checkSnap){
			clearTimeout(config.snapScrollTimer);
			config.snapScrollTimer = setTimeout($.snapScroller, 500);
		}
		
	}
	
	
	$.snapScroller = function(){
		
		// get rid of the existing timer that called the snap
		clearTimeout(config.snapScrollTimer);
		
		// find out how the percentage scrolled is closest to what section..
		if(config.mobile){
			// just go to the current section...
		}else{
			var sectionNum =	Math.round(config.scrollPerc / (1 / (config.sections - 1)));
			$.toggleSection(sectionNum);		
			$.gotoItem(false, sectionNum);			
		}
	}
	
		    
    $.scrollSnapComplete = function() {
    	
 		config.checkSnap = true;
 		// do the img and bg fading stuff in here		
		if(config.changeBG){	

			var bgColor = 		$(settings.scrContent+config.curSection).data('bgColor');
			var bgImg = 		$(settings.scrContent+config.curSection).data('bgImg');			
			var bgType = 		$(settings.scrContent+config.curSection).data('bgType');			

			// animate the bg colour
			if(bgColor) {
				$('body').animate({backgroundColor:bgColor}, {queue:false, duration:500});
				var opacity = 0.3;
				if(bgType) opacity = 0.6;
				$.setDescriptionBG(bgColor, opacity)
			}
			
				
			
			// if alpha > 0 - fade out
			var duration = 600;
			var bgImgSelector = settings.bgImg

			$(bgImgSelector).fadeOut(duration,  function(){
				
				if (bgImg) $('body').addClass('loading');
					
				$(settings.bgImg + ' img').remove();				
				
				$(settings.bgImg).css({	'background-image'	:"none"});
				
				$(settings.bgImg).css('background-image', "url('" + bgImg + "')");
				
				
				if(bgImg){

					$(settings.bgImg).html('<img src="' + bgImg + '">');	
					
					$(settings.bgImg + ' img').load(function() {
						
						if(bgType == 'tile'){
							//it's a tile...set bg
							//$(settings.bgImg).css('background-image', "url('" + bgImg + "')");
							$(settings.bgImg + ' img').remove();
						}else{
							//it's an image...
							$.fn.fullscreenr({ width: 1280,  height: 720, bgID : settings.bgImg + ' img' });
						}

						$(bgImgSelector).fadeIn(600, function(){if (bgImg)$('body').removeClass('loading');});
					});
					
				}
				
			});
		}        
    }
    
    // need to pass the container and the opacity in the arguments
    $.setDescriptionBG = function(hex, opacity) {

      // this is the hex value of the bg color
      if(hex === undefined) hex = 'FFFFFF';
      if(opacity === undefined) opacity = 0.5;

      // if the hex is valid.. ie under 6 chars and might have a hash
      if (!hex.match(/^#?([0-9A-Fa-f]){3}$|^#?([0-9A-Fa-f]){6}$/)) {
        var msg = 'Invalid HEX value';
        $('.separate').val('');
        $('#f_rgb_for_css').val(msg);
        $('#f_rgba_for_css').val(msg);
        return false;
      };


      // remove spaces
      hex = hex.replace(' ','');

      // strip # from HEX
      hex = ( hex.charAt(0) == "#" ? hex.substr(1) : hex );
      // check if 6 letters are provided
      if (hex.length == 6) {
        r = parseInt(hex.substring(0, 2), 16);
        g = parseInt(hex.substring(2, 4), 16);
        b = parseInt(hex.substring(4, 6), 16);
      }
      else if (hex.length == 3) {
        r =  parseInt(hex.substring(0, 1) + hex.substring(0, 1), 16);
        g =parseInt(hex.substring(1, 2) + hex.substring(1, 2), 16);
        b = parseInt(hex.substring(2, 3) + hex.substring(2, 3), 16);
      }
      
      r =  Math.round(r  / 2);
      g = Math.round(g / 2);
      b = Math.round(b / 2);

      // this returns the colours.. need to change this to set the css property of the conainer passed
      //$('#f_rgb_for_css').val('rgb(' + r + ', ' + g + ', ' + b + ')');
      var rgba =  'rgba(' + r + ', ' + g + ', ' + b + ', '   + opacity + ')';
      $(config.descBG).css({background:rgba});

    }
    
    $.navigateMenu = function(dir){
     	var $items = $('#scrollMenu ul li')
    	var $old = $items.filter('.selected'),$new;  
     	
    	if(dir == 'up'){
    		
    		window.log('direction up')
    		// if the current item is the first, exit
    		$new = $old.prev();
    		if($items.index($new) < 0){
    			$.swipeUp();
    		}else{
    			
    		}	
    		//$.swipeUp();
    		window.log($new + ' new item index: ' + $items.index($new))
    		
    	}else{
    		// dir is down...    		
    		window.log('old length: ' + $old.length)
    		if($old.length){
    			// find the current index of the a.hilite class
    			// else, if last, go to the first. 
    			$new = $old.next()
    			if(!$new.length) $new = $old.parent().children(':first')    			
    			window.log('NEXT item: ' + $new)
    			
    		}else{
    			// if no index go to the first
    			//$('#scrollMenu ul li a:first').addClass('hilite')
    			window.log('first item ')
    		}
			
    	} 
    	
		$old.removeClass('selected')
		$new.addClass('selected')
		
    }
    

    window.log = function(){
      log.history = log.history || [];   // store logs to an array for reference
      log.history.push(arguments);
      if(this.console){
        console.log( Array.prototype.slice.call(arguments) );
      }
    };
    
    
    // Fullscreenr Plugin...
    
	$.fn.fullscreenr = function(options) {
		if(options.height === undefined) 	// alert('Please supply the background image height, default values will now be used. These may be very inaccurate.');
		if(options.width === undefined) 	// alert('Please supply the background image width, default values will now be used. These may be very inaccurate.');
		if(options.bgID === undefined) 		// alert('Please supply the background image ID, default #bgimg will now be used.');
		var defaults = { width: 1280,  height: 720, bgID: 'bgImg' };
		var options = $.extend({}, defaults, options); 
		$(document).ready(function() { $(options.bgID).fullscreenrResizer(options);	});
		$(window).bind("resize", function() { $(options.bgID).fullscreenrResizer(options); });		
		return this; 		
	};
	
	
	$.fn.fullscreenrResizer = function(options) {
		// Set bg size
		var ratio = options.height / options.width;	
		// Get browser window size
		var browserwidth = $(window).width();
		var browserheight = $(window).height();
		// Scale the image
		if ((browserheight/browserwidth) > ratio){
		    $(this).height(browserheight);
		    $(this).width(browserheight / ratio);
		} else {
		    $(this).width(browserwidth);
		    $(this).height(browserwidth * ratio);
		}

		// Center the image
		$(this).css('left', (browserwidth - $(this).width())/2);
		$(this).css('top', (browserheight - $(this).height())/2);
		return this; 		
	};    
    
        
})(jQuery);
